//! 网络工具

use reqwest;
use serde::Serialize;
use std::net::{Ipv4Addr, SocketAddr};
use std::str::FromStr;

/// HTTP GET 请求
/// 
/// # 示例
/// 
/// ```
/// use rust_utils::network_utils::http_get;
/// 
/// // 注意：这个测试需要网络连接
/// // let response = http_get("https://httpbin.org/get");
/// // assert!(response.is_ok());
/// ```
pub async fn http_get(url: &str) -> Result<String, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

/// HTTP POST 请求（发送 JSON 数据）
/// 
/// # 示例
/// 
/// ```
/// use rust_utils::network_utils::http_post_json;
/// use serde::{Deserialize, Serialize};
/// 
/// #[derive(Serialize, Deserialize)]
/// struct TestData {
///     name: String,
///     age: u32,
/// }
/// 
/// // 注意：这个测试需要网络连接
/// // let data = TestData {
/// //     name: "Alice".to_string(),
/// //     age: 30,
/// // };
/// // let response = http_post_json("https://httpbin.org/post", &data);
/// // assert!(response.is_ok());
/// ```
pub async fn http_post_json<T: Serialize>(url: &str, data: &T) -> Result<String, reqwest::Error> {
    let client = reqwest::Client::new();
    let response = client.post(url).json(data).send().await?;
    let body = response.text().await?;
    Ok(body)
}

/// 检查 IPv4 地址是否有效
/// 
/// # 示例
/// 
/// ```
/// use rust_utils::network_utils::is_valid_ipv4;
/// 
/// assert_eq!(is_valid_ipv4("192.168.1.1"), true);
/// assert_eq!(is_valid_ipv4("256.1.1.1"), false);
/// assert_eq!(is_valid_ipv4("not.an.ip.address"), false);
/// ```
pub fn is_valid_ipv4(ip: &str) -> bool {
    Ipv4Addr::from_str(ip).is_ok()
}

/// 检查端口是否有效（1-65535）
/// 
/// # 示例
/// 
/// ```
/// use rust_utils::network_utils::is_valid_port;
/// 
/// assert_eq!(is_valid_port(80), true);
/// assert_eq!(is_valid_port(0), false);
/// assert_eq!(is_valid_port(65535), true);
/// ```
pub fn is_valid_port(port: u16) -> bool {
    port > 0
}

/// 解析 Socket 地址
/// 
/// # 示例
/// 
/// ```
/// use rust_utils::network_utils::parse_socket_addr;
/// 
/// let addr = parse_socket_addr("127.0.0.1:8080");
/// assert!(addr.is_ok());
/// 
/// let invalid_addr = parse_socket_addr("invalid:address");
/// assert!(invalid_addr.is_err());
/// ```
pub fn parse_socket_addr(addr: &str) -> Result<SocketAddr, std::net::AddrParseError> {
    SocketAddr::from_str(addr)
}

/// URL 编码
/// 
/// # 示例
/// 
/// ```
/// use rust_utils::network_utils::url_encode;
/// 
/// let encoded = url_encode("hello world");
/// assert_eq!(encoded, "hello%20world");
/// ```
pub fn url_encode(input: &str) -> String {
    urlencoding::encode(input).to_string()
}

/// URL 解码
/// 
/// # 示例
/// 
/// ```
/// use rust_utils::network_utils::url_decode;
/// 
/// let decoded = url_decode("hello%20world");
/// assert_eq!(decoded, Ok("hello world".to_string()));
/// ```
pub fn url_decode(input: &str) -> Result<String, std::string::FromUtf8Error> {
    urlencoding::decode(input).map(|s| s.to_string())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_is_valid_ipv4() {
        assert_eq!(is_valid_ipv4("192.168.1.1"), true);
        assert_eq!(is_valid_ipv4("256.1.1.1"), false);
        assert_eq!(is_valid_ipv4("not.an.ip.address"), false);
        assert_eq!(is_valid_ipv4("127.0.0.1"), true);
    }

    #[test]
    fn test_is_valid_port() {
        assert_eq!(is_valid_port(80), true);
        assert_eq!(is_valid_port(0), false);
        assert_eq!(is_valid_port(65535), true);
    }

    #[test]
    fn test_parse_socket_addr() {
        let addr = parse_socket_addr("127.0.0.1:8080");
        assert!(addr.is_ok());
        
        let invalid_addr = parse_socket_addr("invalid:address");
        assert!(invalid_addr.is_err());
    }

    #[test]
    fn test_url_encode() {
        let encoded = url_encode("hello world");
        assert_eq!(encoded, "hello%20world");
        
        let encoded = url_encode("a+b@c.com");
        assert_eq!(encoded, "a%2Bb%40c.com");
    }

    #[test]
    fn test_url_decode() {
        let decoded = url_decode("hello%20world");
        assert_eq!(decoded, Ok("hello world".to_string()));
        
        let decoded = url_decode("a%2Bb%40c.com");
        assert_eq!(decoded, Ok("a+b@c.com".to_string()));
    }
}